#include "stdafx.h"
#include "Lambda.h"

#include <algorithm>
#include <vector>
#include <iostream>
#include <functional>

void lambdaAction(void)
{
	std::cout << "Lambda Action start ..." << std::endl;

	// Create a vector object that contains 10 elements
	std::vector<int> v(10);
	int index(0);
	std::generate(std::begin(v), std::end(v), [&] { return index++; });

	// Count the number of even numbers in the vector by 
	// using the for_each function and a lambda
	int evenCount(0);

	// why it can not be [&, evenCount]?
	// since they are different!
	// Recap:
	// The default capture mode specifies whether capture variables
	// that <b> you do not explicitly specify are captured by value or by reference. 
	// </b>
	std::for_each(std::begin(v), std::end(v), [&evenCount](int n) {
		std::cout << "Fetch " << n;
		if (n % 2 == 0) {
			std::cout << " is even " << std::endl;
			++evenCount;
		}
		else {
			std::cout << " is odd " << std::endl;
		}
	});

	// Print the count of even numbers to the console
	std::cout << "There are " << evenCount << 
		" even numbers in the vector." << std::endl;
}

void funcObjectAction(void)
{
	std::cout << "Lambda Function Object Action start ..." << std::endl;

	// Create a vector object that contains 10 elements
	std::vector<int> v(10);
	int index(0);
	std::generate(std::begin(v), std::end(v), [&]{ return index++; });

	// Count the number of even numbers in the vector by
	// using the for_each function and a function object.
	int evenCount(0);
	std::for_each (std::begin(v), std::end(v), FuncClass(evenCount));
}

// The number of elements in the vector
const int elementCount = 9;
void lambdaProfileAction(void)
{
	std::cout << "Lambda Profile Action start ..." << std::endl;

	// Create a vector object with each element set to 1.
	std::vector<int> v(elementCount, 1);

	// These variables hold the previous two element of the vector.
	int x(1);
	int y(1);

	// Assign each element in the vector to the sum of the
	// previous two elements
	//std::generate_n(v.begin() + 2, elementCount - 2, [=]() mutable throw() -> int {
	//	// or std::generate_n(v.begin() + 2, elementCount - 2, [&]() throw() -> int {
	//	// But they are different, in the option 1, the x,y still hold orignal value 1
	//	// after these operations;
	//	// in the option 2, the x,y will change it's value after these operations.

	//	// Generate current value.
	//	int n = x + y;

	//	// Update previous two values.
	//	x = y;
	//	y = n;
	//	
	//	return n;
	//});

	// Refine: not need element count invoked
	std::generate(std::begin(v) + 2, std::end(v), [=]() mutable {
		int n = x + y;
		x = y;
		y = n;
		
		std::cout << "(x,y) = " << "(" << x << "," << y << ")";
		return n;
	});

	std::cout << "\nWatch (x,y) value: " << x << ", " << y << std::endl;

	// Print the contents of the vector.
	std::for_each(std::begin(v), std::end(v), [&](int n) {
		std::cout << n << " ";
	});
	std::cout << std::endl;
}

void mutableTestAction(void)
{
	std::cout << "Lambda Mutalbe Action start ..." << std::endl;

	int m = 0, n = 0;
	[&, n] (int a) mutable throw() { m = ++n + a; }(4);

	std::cout << m << std::endl << n << std::endl;
}

void declareAction(void)
{
	// Assign the lambda expression that adds two numbers to an auto variable.
	auto f1 = [] (int x, int y) { return x + y; };

	// Assign the same lambda expression to a function object.
	std::function<int (int, int)> f2 = [] (int x, int y) { return x + y; };
}